package base_init

import (
	"github.com/go-yaml/yaml"
	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
	"go-likaladi-shop/common/base_config"
	"go.uber.org/zap"
)

func InitNacosService(serviceDataId string, nacosConfig base_config.NacosConfig, serviceYaml interface{}) config_client.IConfigClient {
	//创建nacos客户端
	nacosClient := CreateNacosConnClient(nacosConfig)

	//通过dataId和group解析nacos文件配置内容映射到对应的struct
	NacosContentMappingStruct(nacosClient, serviceDataId, "DEFAULT_GROUP", serviceYaml)

	//通过dataId和group进行监听对应nacos文件变化, 进行映射到对应的struct
	NacosListenConfig(nacosClient, serviceDataId, "DEFAULT_GROUP", serviceYaml)

	return nacosClient
}

// CreateNacosConnClient 负责创建 Nacos 配置中心客户端
// 参数:
// - nacosConfig: 包含 Nacos 服务器信息的配置结构体
// 返回值:
// - config_client.IConfigClient: Nacos 配置客户端接口
func CreateNacosConnClient(nacosConfig base_config.NacosConfig) config_client.IConfigClient {
	// 配置 Nacos 服务器信息
	serverConfig := []constant.ServerConfig{
		{
			IpAddr: nacosConfig.Host,         // Nacos 服务器地址
			Port:   uint64(nacosConfig.Port), // Nacos 端口号
		},
	}

	// 配置 Nacos 客户端信息
	clientConfig := &constant.ClientConfig{
		NamespaceId: nacosConfig.NamespaceId, // Nacos 命名空间 ID
	}

	// 创建 Nacos 配置客户端
	client, err := clients.NewConfigClient(vo.NacosClientParam{
		ClientConfig:  clientConfig, // Nacos 客户端配置
		ServerConfigs: serverConfig, // Nacos 服务器配置
	})
	if err != nil {
		//zap.S().Fatalf()（会直接 os.Exit(1)，直接退出, 适合初始化）
		zap.S().Fatalf("创建 Nacos 客户端失败: %v", err)
	}

	return client
}

// NacosContentMappingStruct 从 Nacos 获取配置内容并映射到指定的结构体
//
// 参数:
//   - client: Nacos 配置客户端，用于获取配置内容
//   - dataId: 配置的 Data ID，用于标识 Nacos 中的特定配置
//   - group: 配置所属的分组，默认为 "DEFAULT_GROUP"
//   - ncosYaml: 目标结构体指针，用于存储解析后的 YAML 配置数据
//
// 逻辑流程:
// 1. 调用 `client.GetConfig` 获取 Nacos 中的 YAML 配置数据
// 2. 如果获取失败，使用 `zap.S().Fatalf` 记录错误日志并终止程序
// 3. 解析 YAML 配置内容，并将其映射到 `ncosYaml` 结构体
// 4. 解析完成后，`ncosYaml` 结构体将包含最新的 Nacos 配置信息
func NacosContentMappingStruct(client config_client.IConfigClient, dataId, group string, ncosYaml interface{}) {
	// 获取 Nacos 配置中心存储的配置内容
	content, err := client.GetConfig(vo.ConfigParam{
		DataId: dataId, // 配置的 Data ID，Nacos 中的唯一标识
		Group:  group,  // 配置所属的分组
	})
	if err != nil {
		// 记录错误日志并终止程序（适用于服务初始化时的关键配置）
		zap.S().Fatalf("获取配置失败: %v", err)
	}

	// 解析 YAML 配置，并更新到指定的结构体
	updateConfig(content, ncosYaml)
}

// updateConfig 负责将 YAML 配置内容解析到结构体中
// 参数:
// - content: Nacos 获取的 YAML 配置内容
// - ncosYaml: 需要更新的结构体指针
func updateConfig(content string, ncosYaml any) {
	err := yaml.Unmarshal([]byte(content), ncosYaml)
	if err != nil {
		//zap.S().Fatalf()（会直接 os.Exit(1)，直接退出, 适合初始化）
		zap.S().Fatalf("YAML 解析失败: %v", err)
	}

	// 记录最新的配置内容
	zap.S().Infof("配置更新: %+v", ncosYaml)
}

// NacosListenConfig 监听 Nacos 配置变化，并在发生变化时更新配置
// 参数:
// - client: Nacos 配置客户端
// - nacosConfig: Nacos 配置结构体
// - ncosYaml: 需要更新的配置结构体指针
func NacosListenConfig(client config_client.IConfigClient, dataId, group string, ncosYaml any) {
	// 监听 Nacos 配置变化，动态更新配置
	err := client.ListenConfig(vo.ConfigParam{
		DataId: dataId, // 配置的 Data ID
		Group:  group,  // 配置分组
		OnChange: func(namespace, group, dataId, data string) {
			// 当配置发生变化时，执行更新逻辑
			zap.S().Infof("配置发生变化，新的配置内容:")
			updateConfig(data, ncosYaml)
		},
	})
	if err != nil {
		zap.S().Errorf("监听配置变化失败: %v", err)
	}
}
